package com.quectel.emp.controller.schedulingapply;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.URLUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.quectel.business.common.dept.DeptPersonMsgBusiness;
import com.quectel.business.common.file.FileBusiness;
import com.quectel.business.common.schedulingapply.SchedulingApplyBusiness;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.constant.OrderCodePrefixConstants;
import com.quectel.constant.core.dept.DeptPersonConstants;
import com.quectel.constant.core.scheduling.SchedulingApplyConstants;
import com.quectel.constant.core.scheduling.SchedulingAuditPipelineSeqConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.dept.dto.DeptPersonDto;
import com.quectel.core.module.dept.service.DeptPersonService;
import com.quectel.core.module.file.vo.FileDataVO;
import com.quectel.core.module.scheduling.dto.SchedulingAuditPipelineDto;
import com.quectel.core.module.scheduling.dto.SchedulingAuditPipelineSeqDeptPersonDto;
import com.quectel.core.module.scheduling.dto.SchedulingAuditPipelineSeqDto;
import com.quectel.core.module.scheduling.dto.SchedulingWorkOvertimeConfigDto;
import com.quectel.core.module.scheduling.service.SchedulingAuditPipelineSeqDeptPersonService;
import com.quectel.core.module.scheduling.service.SchedulingAuditPipelineService;
import com.quectel.core.module.schedulingapply.dto.SchedulingApplyLeaveRecordDto;
import com.quectel.core.module.schedulingapply.dto.SchedulingApplyRecordAuditLogDto;
import com.quectel.core.module.schedulingapply.dto.SchedulingApplyRecordAuditPersonDto;
import com.quectel.core.module.schedulingapply.dto.SchedulingApplyRecordDto;
import com.quectel.core.module.schedulingapply.dto.vo.SchedulingApplyCountVO;
import com.quectel.core.module.schedulingapply.dto.vo.SchedulingTimeVO;
import com.quectel.core.module.schedulingapply.service.SchedulingApplyRecordAuditLogService;
import com.quectel.core.module.schedulingapply.service.SchedulingApplyRecordAuditPersonService;
import com.quectel.core.module.schedulingapply.service.SchedulingApplyRecordService;
import com.quectel.emp.controller.BaseController;
import com.quectel.emp.util.SessionHolder;
import com.quectel.emp.vo.schedulingapply.SchedulingCanResumptionVO;
import com.quectel.util.common.*;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.kit.OrderUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/07/13 19:14
 */
@RestController
@RequestMapping("schedulingApplyRecord")
@Tag(name = "SchedulingApplyRecordController", description = "申请记录相关api")
public class SchedulingApplyRecordController extends BaseController {

    @DubboReference
    private SchedulingApplyRecordService schedulingApplyRecordService;
    @DubboReference
    private SchedulingAuditPipelineService schedulingAuditPipelineService;
    @DubboReference
    private SchedulingApplyRecordAuditPersonService schedulingApplyRecordAuditPersonService;
    @DubboReference
    private SchedulingAuditPipelineSeqDeptPersonService schedulingAuditPipelineSeqDeptPersonService;
    @DubboReference
    private DeptPersonService deptPersonService;

    @Autowired
    private SchedulingApplyBusiness schedulingApplyBusiness;
    @Autowired
    private FileBusiness fileBusiness;
    @Autowired
    private DeptPersonMsgBusiness deptPersonMsgBusiness;
    @Autowired
    private SchedulingApplyRecordAuditLogService schedulingApplyRecordAuditLogService;


    /**
     * @return
     */
    @GetMapping("overtimeConfig")
    @Operation(summary = "加班简易说明")
    public Response<List<String>> overtimeConfig() {
        SessionHolder.checkEmp();

        Response<SchedulingWorkOvertimeConfigDto> overtimeConfigByPerson = schedulingApplyBusiness.getOvertimeConfigByPerson(SessionHolder.getEmp().getId());
        if (!overtimeConfigByPerson.isSuccess()) {
            return Response.error(overtimeConfigByPerson.getMessage());
        }
        List<String> list = new ArrayList<>();
        SchedulingWorkOvertimeConfigDto data = overtimeConfigByPerson.getData();

        if (data.getWorkDayConfig() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            if (data.getWorkDayConfig().getStatus().equals(SystemConstants.YES)) {
                if (SystemConstants.YES.equals(data.getWorkDayConfig().getSettlementType())) {
                    stringBuilder.append("工作日加班仅做记录");
                } else {
                    stringBuilder.append("工作日加班时长按1:");
                    stringBuilder.append(data.getWorkDayConfig().getRate());
                    stringBuilder.append("结算为");
                    stringBuilder.append(SysCodeUtils.easyToGetName(SysCodeKeyConstants.SCHEDULING_LEAVE_TYPE, String.valueOf(data.getWorkDayConfig().getDeductionHolidayType())));
                }

            } else {
                stringBuilder.append("工作日不允许加班");
            }
            list.add(stringBuilder.toString());
        }
        if (data.getRestDayConfig() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            if (data.getRestDayConfig().getStatus().equals(SystemConstants.YES)) {
                if (SystemConstants.YES.equals(data.getRestDayConfig().getSettlementType())) {
                    stringBuilder.append("休息日加班仅做记录");
                } else {
                    stringBuilder.append("休息日日加班时长按1:");
                    stringBuilder.append(data.getRestDayConfig().getRate());
                    stringBuilder.append("结算为");
                    stringBuilder.append(SysCodeUtils.easyToGetName(SysCodeKeyConstants.SCHEDULING_LEAVE_TYPE, String.valueOf(data.getRestDayConfig().getDeductionHolidayType())));

                }
            } else {
                stringBuilder.append("休息日不允许加班");
            }
            list.add(stringBuilder.toString());
        }
        if (data.getHolidayConfig() != null) {
            StringBuilder stringBuilder = new StringBuilder();
            if (data.getHolidayConfig().getStatus().equals(SystemConstants.YES)) {
                if (SystemConstants.YES.equals(data.getHolidayConfig().getSettlementType())) {
                    stringBuilder.append("节假日加班仅做记录");
                } else {
                    stringBuilder.append("节假日加班时长按1:");
                    stringBuilder.append(data.getHolidayConfig().getRate());
                    stringBuilder.append("结算为");
                    stringBuilder.append(SysCodeUtils.easyToGetName(SysCodeKeyConstants.SCHEDULING_LEAVE_TYPE, String.valueOf(data.getHolidayConfig().getDeductionHolidayType())));
                }

            } else {
                stringBuilder.append("节假日日不允许加班");
            }
            list.add(stringBuilder.toString());
        }

        return Response.<List<String>>ok().wrap(list);
    }


    /**
     * @return
     */
    @GetMapping("auditPipeline")
    @Operation(summary = "查询申请记录的审批流程")
    public Response<List<SchedulingApplyRecordAuditPersonDto>> auditPipeline(
            @Parameter @RequestParam Byte applyType
    ) {
        SessionHolder.checkEmp();

        SchedulingAuditPipelineDto auditPipelineDto = schedulingAuditPipelineService.selectByVillageAndType(SessionHolder.getEmp().getVillageId()
                , applyType);
        Response response = schedulingApplyBusiness.checkPipeline(auditPipelineDto);
        if (!response.isSuccess()) {
            return Response.error(response.getMessage());
        }

        List<SchedulingAuditPipelineSeqDto> seqs = auditPipelineDto == null
                ? new ArrayList<>()
                : auditPipelineDto.getAuditPipelineSeqDtos();
        //2.初始化节点
        Integer nextSeqNumber = SchedulingApplyConstants.CURRENT_AT_SEQ_OF_BEGIN;
        //3.实际审批节点序号
        Integer sqeNum = SchedulingApplyConstants.CURRENT_AT_SEQ_OF_BEGIN;
        List<SchedulingApplyRecordAuditPersonDto> nextAuditPersonList = new ArrayList<>();
        while (true) {
            SchedulingAuditPipelineSeqDto nextSeqDto = null;
            final Integer finalNextSqeNum = nextSeqNumber;
            final Integer finalSqeNum = sqeNum;
            Optional<SchedulingAuditPipelineSeqDto> nextItem = seqs.stream().filter(o -> finalNextSqeNum.equals(o.getSeq()))
                    .findFirst();
            if (nextItem.isPresent()) {
                nextSeqDto = nextItem.get();
            }
            //5.2查询审批节点人员
            if (nextSeqDto != null) {
                List<Long> personIds;
                if (SchedulingAuditPipelineSeqConstants.AUDIT_TYPE_DEPARTMENT_DESIGNATED_PERSON
                        .equals(nextSeqDto.getAuditType())) {
                    List<SchedulingAuditPipelineSeqDeptPersonDto> personDtos = schedulingAuditPipelineSeqDeptPersonService
                            .selectBySeqId(nextSeqDto.getId());
                    personIds = personDtos.stream()
                            .map(SchedulingAuditPipelineSeqDeptPersonDto::getDeptPersonId)
                            .collect(Collectors.toList());
                } else {
                    List<DeptPersonDto> personDtos = null;
                    if (nextSeqDto.getDeptId() == null || nextSeqDto.getDeptId().equals(-1L)) {
                        personDtos = deptPersonService.selectByDeptId(SessionHolder.getEmp().getDeptId());
                    } else {
                        personDtos = deptPersonService.selectByDeptId(nextSeqDto.getDeptId());
                    }
                    final Byte finalNextAuditType = nextSeqDto.getAuditType();
                    personIds = personDtos.stream()
                            .filter(o -> SchedulingAuditPipelineSeqConstants.AUDIT_TYPE_ALL_PERSONNEL_OF_THE_DEPARTMENT.equals(
                                    finalNextAuditType) || DeptPersonConstants.DEPT_ADMIN.equals(o.getIsAdmin()))
                            .map(DeptPersonDto::getId)
                            .collect(Collectors.toList());
                }
                if (personIds.isEmpty()) {
                    throw new CheckErrorException("审批流下一序列没有审批人");
                }

                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < 3 && i < personIds.size(); i++) {
                    DeptPersonDto deptPersonDto = deptPersonService.selectCacheById(personIds.get(i));
                    if (deptPersonDto != null) {
                        stringBuilder.append(deptPersonDto.getName());
                        stringBuilder.append(",");
                    }
                }
                String s = StringUtils.removeEnd(stringBuilder.toString(), ",");
                String personNames = personIds.size() == 1 ? s : s + "等";
                SchedulingApplyRecordAuditPersonDto schedulingApplyRecordAuditPersonDto = new SchedulingApplyRecordAuditPersonDto();
                schedulingApplyRecordAuditPersonDto.setCurrentAtSeq(finalSqeNum);
                schedulingApplyRecordAuditPersonDto.setDeptPersonName(personNames);
                nextAuditPersonList.add(schedulingApplyRecordAuditPersonDto);

                //序号进位
                nextSeqNumber++;
                sqeNum++;
            } else {
                break;
            }
        }
        SchedulingApplyRecordAuditPersonDto schedulingApplyRecordAuditPersonDto = new SchedulingApplyRecordAuditPersonDto();
        schedulingApplyRecordAuditPersonDto.setCurrentAtSeq(SchedulingApplyConstants.CURRENT_AT_SEQ_OF_CREATOR);
        schedulingApplyRecordAuditPersonDto.setDeptPersonName(SessionHolder.getEmp().getName());
        nextAuditPersonList.add(0, schedulingApplyRecordAuditPersonDto);
        return Response.<List<SchedulingApplyRecordAuditPersonDto>>ok().wrap(nextAuditPersonList);
    }

    /**
     * @return
     */
    @GetMapping("applyRecordCount")
    @Operation(summary = "本人的申请记录统计")
    public Response<List<SchedulingApplyCountVO>> applyRecordCount(
            @Parameter(description = "查询范围,默认查询待审核的;传值1:审批中的申请(记录状态0);传值2:已完成的申请(记录状态-2,-2,1,2,3);传值3:草稿(记录状态-3).状态对应的字典值:SchedulingAuditStatus") @RequestParam(defaultValue = "0") String typeFlag

    ) {
        SessionHolder.checkEmp();
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getTenantId), SessionHolder.getEmp().getTenantId());
        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getVillageId), SessionHolder.getEmp().getVillageId());
        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getApplyDeptPersonId), SessionHolder.getEmp().getId());

        Byte[] statuses = null;
        if (typeFlag.equals(SchedulingApplyConstants.AUDITING)) {
            statuses = SchedulingApplyConstants.AUDITING_STATUSES;
        } else if (typeFlag.equals(SchedulingApplyConstants.FINISHED)) {
            statuses = SchedulingApplyConstants.FINISHED_STATUSES;
        } else if (typeFlag.equals(SchedulingApplyConstants.NOT_SUBMITTED)) {
            statuses = SchedulingApplyConstants.NOT_SUBMITTED_STATUSES_STATUSES;
        }
        if (statuses == null) {
            return Response.error("查询范围不正确");
        }
        request.put(SystemConstants.STATUSES, statuses);

        List<SchedulingApplyCountVO> schedulingApplyCountVOS = schedulingApplyRecordService.applyRecordCount(request.getParams());

        return Response.<List<SchedulingApplyCountVO>>ok().wrap(schedulingApplyCountVOS);
    }

    /**
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("list")
    @Operation(summary = "分页获取申请记录列表,本人的申请记录")
    public Response<Page<SchedulingApplyRecordDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "传值1:审批中的申请(记录状态0);传值2:已完成的申请(记录状态-2,-2,1,2,3);传值3:草稿(记录状态-3).状态对应的字典值:SchedulingAuditStatus") @RequestParam String typeFlag,
            @Parameter(description = "类型,字典值") @RequestParam(required = false) Integer applyType
    ) {
        SessionHolder.checkEmp();
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getTenantId), SessionHolder.getEmp().getTenantId());
        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getVillageId), SessionHolder.getEmp().getVillageId());
        request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getApplyDeptPersonId), SessionHolder.getEmp().getId());
        if (applyType != null) {
            request.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getApplyType), applyType);
        }

        Byte[] statuses = null;
        if (typeFlag.equals(SchedulingApplyConstants.AUDITING)) {
            statuses = SchedulingApplyConstants.AUDITING_STATUSES;
        } else if (typeFlag.equals(SchedulingApplyConstants.FINISHED)) {
            statuses = SchedulingApplyConstants.FINISHED_STATUSES;
        } else if (typeFlag.equals(SchedulingApplyConstants.NOT_SUBMITTED)) {
            statuses = SchedulingApplyConstants.NOT_SUBMITTED_STATUSES_STATUSES;
        }
        if (statuses == null) {
            return Response.error("查询范围不正确");
        }
        request.put(SystemConstants.STATUSES, statuses);

        int total = schedulingApplyRecordService.queryTotal(request.getParams());

        List<SchedulingApplyRecordDto> list = null;
        if (total > 0) {
            list = schedulingApplyRecordService.queryList(request.getParams());
            list.forEach(schedulingApplyRecordDto -> {
                //填充表单数据
                SchedulingApplyRecordDto.BaseFormData formData = schedulingApplyBusiness.getFormData(schedulingApplyRecordDto.getApplyType(), schedulingApplyRecordDto.getFormDataJson());
                schedulingApplyRecordDto.setFormData(formData);
            });
        } else {
            list = new ArrayList<>();
        }

        Page<SchedulingApplyRecordDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<SchedulingApplyRecordDto>>ok().wrap(page);
    }

    /**
     * 编辑查询反显
     *
     * @param id
     * @return
     */
    @GetMapping("info/{id}")
    @Operation(summary = "在编辑时根据id查询申请记录详情")
    public Response<SchedulingApplyRecordDto> info(@PathVariable("id") Long id) {

        Map<String, Object> params = new HashMap<>();
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getTenantId), SessionHolder.getEmp().getTenantId());
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getVillageId), SessionHolder.getEmp().getVillageId());
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getApplyDeptPersonId), SessionHolder.getEmp().getId());
        if (schedulingApplyRecordService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        SchedulingApplyRecordDto schedulingApplyRecordDto = schedulingApplyRecordService.selectById(id);
        //填充表单数据
        SchedulingApplyRecordDto.BaseFormData formData = schedulingApplyBusiness.getFormData(schedulingApplyRecordDto.getApplyType(), schedulingApplyRecordDto.getFormDataJson());
        schedulingApplyRecordDto.setFormData(formData);

        List<SchedulingApplyRecordAuditLogDto> auditLogs = schedulingApplyBusiness.getAuditLogs(schedulingApplyRecordDto);
        schedulingApplyRecordDto.setAuditLogs(auditLogs);

        return Response.<SchedulingApplyRecordDto>ok().wrap(schedulingApplyRecordDto);
    }

    /**
     * 计算请假时长
     *
     * @return
     */
    @GetMapping("calApplyTimeLength")
    @Operation(summary = "计算申请时长")
    public Response<SchedulingTimeVO> calApplyTimeLength(
            @Parameter(description = "申请类型") @RequestParam Byte applyType,
            @Parameter(description = "formData") @RequestParam String formData
    ) {
        SessionHolder.checkEmp();
        String decode = URLUtil.decode(formData);
        JsonNode parse = JacksonUtils.parse(decode);
        SchedulingApplyConstants.ApplyTypeEnum byType = SchedulingApplyConstants.ApplyTypeEnum.getByType(applyType);
        if (byType == null) {
            return null;
        }
        SchedulingTimeVO timeLength = null;
        switch (byType) {
            case APPLY_LEAVE:
                timeLength = schedulingApplyBusiness.getTimeLength(parse.get(LambdaUtil.getFieldName(SchedulingApplyLeaveRecordDto::getLeaveId)).asLong(), parse.get(LambdaUtil.getFieldName(SchedulingApplyLeaveRecordDto::getStartTime)).asText(), parse.get(LambdaUtil.getFieldName(SchedulingApplyLeaveRecordDto::getEndTime)).asText());
                break;
            case OVER_TIME:
            case OUT:
            case TRIP:
            default:
                timeLength = schedulingApplyBusiness.getTimeLength(applyType,  parse.get(LambdaUtil.getFieldName(SchedulingApplyLeaveRecordDto::getStartTime)).asText(), parse.get(LambdaUtil.getFieldName(SchedulingApplyLeaveRecordDto::getEndTime)).asText());

        }

        return Response.<SchedulingTimeVO>ok().wrap(timeLength);
    }


    /**
     * 销假申请列表
     *
     * @return
     */
    @GetMapping("canSelectRecordList")
    @Operation(summary = "查询本月可销假申请列表，过了本月则无法销假")
    public Response<List<SchedulingCanResumptionVO>> canSelectRecordList(
    ) {
        SessionHolder.checkEmp();
        Date now = new Date();
        String startDate = DateUtils.format(DateUtil.beginOfMonth(now), DateUtils.FormatType.COMMON);
        String endDate = DateUtils.format(DateUtil.endOfMonth(now), DateUtils.FormatType.COMMON);

        Byte[] statuses = new Byte[]{SchedulingApplyConstants.APPROVED_STATUS};
        //已通过的申请列表
        List<SchedulingApplyRecordDto> applyRecordByTypeAndTime = schedulingApplyBusiness.getApplyRecordByTypeAndTime(
                SessionHolder.getEmp().getTenantId(),
                SessionHolder.getEmp().getVillageId(),
                SessionHolder.getEmp().getId(),
                startDate,
                endDate,
                new Byte[]{SchedulingApplyConstants.ApplyTypeEnum.APPLY_LEAVE.getType(), SchedulingApplyConstants.ApplyTypeEnum.TRIP.getType(), SchedulingApplyConstants.ApplyTypeEnum.OUT.getType()},
                statuses
        );
        if (CollectionUtils.isNotEmpty(applyRecordByTypeAndTime)) {
            List<SchedulingCanResumptionVO> collect = applyRecordByTypeAndTime.stream().map(schedulingApplyRecordDto -> {
                SchedulingCanResumptionVO schedulingCanResumptionVO = new SchedulingCanResumptionVO();
                schedulingApplyRecordDto.setFormData(schedulingApplyBusiness.getFormData(schedulingApplyRecordDto.getApplyType(), schedulingApplyRecordDto.getFormDataJson()));
                schedulingCanResumptionVO.setSchedulingApplyRecord(schedulingApplyRecordDto);
                schedulingCanResumptionVO.setId(schedulingApplyRecordDto.getId());
                schedulingCanResumptionVO.setOrderNo(schedulingApplyRecordDto.getOrderNo());
                schedulingCanResumptionVO.setName(SysCodeUtils.easyToGetName(SysCodeKeyConstants.SCHEDULING_AUDIT_PIPELINE_TYPE, String.valueOf(schedulingApplyRecordDto.getApplyType())));
                SchedulingApplyRecordDto.BaseFormData baseFormData = schedulingApplyBusiness.getFormData(schedulingApplyRecordDto.getApplyType(), schedulingApplyRecordDto.getFormDataJson());
                if (SchedulingApplyConstants.ApplyTypeEnum.APPLY_LEAVE.getType().equals(schedulingApplyRecordDto.getApplyType())) {
                    assert baseFormData instanceof SchedulingApplyRecordDto.LeaveFormData;
                    SchedulingApplyRecordDto.LeaveFormData formData = (SchedulingApplyRecordDto.LeaveFormData) baseFormData;
                    schedulingCanResumptionVO.setStartTime(formData.getStartTime());
                    schedulingCanResumptionVO.setEndTime(formData.getEndTime());
                    schedulingCanResumptionVO.setTimeLength(formData.getTimeLength());
                    schedulingCanResumptionVO.setTimeUnit(formData.getTimeUnit());
                }
                if (SchedulingApplyConstants.ApplyTypeEnum.TRIP.getType().equals(schedulingApplyRecordDto.getApplyType())) {
                    assert baseFormData instanceof SchedulingApplyRecordDto.TripFormData;
                    SchedulingApplyRecordDto.TripFormData formData = (SchedulingApplyRecordDto.TripFormData) baseFormData;
                    if (CollectionUtils.isNotEmpty(formData.getTripDataList())) {
                        schedulingCanResumptionVO.setStartTime(formData.getTripDataList().get(0).getStartTime());
                        schedulingCanResumptionVO.setEndTime(formData.getTripDataList().get(0).getEndTime());
                        schedulingCanResumptionVO.setTimeLength(formData.getTripDataList().get(0).getTimeLength());
                        schedulingCanResumptionVO.setTimeUnit(formData.getTripDataList().get(0).getTimeUnit());
                    }
                }
                if (SchedulingApplyConstants.ApplyTypeEnum.OUT.getType().equals(schedulingApplyRecordDto.getApplyType())) {
                    assert baseFormData instanceof SchedulingApplyRecordDto.OutFormData;
                    SchedulingApplyRecordDto.OutFormData formData = (SchedulingApplyRecordDto.OutFormData) baseFormData;
                    schedulingCanResumptionVO.setStartTime(formData.getStartTime());
                    schedulingCanResumptionVO.setEndTime(formData.getEndTime());
                    schedulingCanResumptionVO.setTimeLength(formData.getTimeLength());
                    schedulingCanResumptionVO.setTimeUnit(formData.getTimeUnit());

                }
                return schedulingCanResumptionVO;
            }).collect(Collectors.toList());
            return Response.<List<SchedulingCanResumptionVO>>ok().wrap(collect);
        } else {
            return Response.<List<SchedulingCanResumptionVO>>ok().wrap(Collections.emptyList());
        }
    }


    /**
     * 提交审批记录
     *
     * @return
     */
    @PostMapping(value = "submit", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    @Operation(summary = "提交申请记录")
    public Response submit(
            @Parameter(description = "记录id") @RequestParam(value = "recordId", required = false) Long recordId,
            @Parameter(description = "审核类型") @RequestParam(value = "applyType") Byte applyType,
            @Parameter(description = "表单内容") @RequestParam(value = "formData") String formDataJson,
            @Parameter(description = "图片列表") @RequestParam(value = "extFiles", required = false) MultipartFile[] extFiles
    ) {
        SessionHolder.checkEmp();
        formDataJson = URLUtil.decode(formDataJson);
        //是否是草稿 如果是草稿则需要申请
        SchedulingApplyRecordDto dbRecord = null;
        SchedulingApplyRecordDto.BaseFormData dbFormData = null;
        if (recordId != null) {
            dbRecord = schedulingApplyRecordService.selectById(recordId);

            //校验草稿
            Response response = schedulingApplyBusiness.checkDraft(dbRecord, SessionHolder.getEmp().getId());
            if (!response.isSuccess()) {
                return Response.error(response.getMessage());
            }
            //获取表单数据
            dbFormData = dbRecord.getFormData();
        }
        SchedulingApplyRecordDto.BaseFormData formData = schedulingApplyBusiness.getFormData(applyType, formDataJson);
        if (formData == null) {
            return Response.error("提交数据有误");
        }
        //填充人员信息
        formData.setPersonId(SessionHolder.getEmp().getId());
        //填充附件标识
        formData.setExtFileFlag(getExtFilesFlag(extFiles, formData, dbFormData));

        //校验审批流
        SchedulingAuditPipelineDto schedulingAuditPipelineDto = schedulingAuditPipelineService.selectByVillageAndType(SessionHolder.getEmp().getVillageId(), applyType);
        Response pipelineCheckResult = schedulingApplyBusiness.checkPipeline(schedulingAuditPipelineDto);
        if (!pipelineCheckResult.isSuccess()) {
            return Response.error(pipelineCheckResult.getMessage());
        }

        //打包申请时长
        formData = schedulingApplyBusiness.packTimeLength(applyType, formData);
        if (formData == null) {
            return Response.error("提交数据有误");
        }
        //校验申请
        Response applyCheckResponse = schedulingApplyBusiness.checkApply(applyType, formData);
        if (!applyCheckResponse.isSuccess()) {
            return Response.error(applyCheckResponse.getMessage());
        }

        //保存到miniIO
        Response<List<FileDataVO>> saveFileResult = saveFileToMiniIO(extFiles);
        if (!saveFileResult.isSuccess()) {
            return Response.error(saveFileResult.getMessage());
        }
        formData.setExtFiles(mergeFileList(saveFileResult.getData(), formData, dbFormData));

        SchedulingApplyRecordDto schedulingApplyRecordDto = initRecord(applyType, formData, dbRecord);
        schedulingApplyRecordDto.setStatus(SchedulingApplyConstants.INIT_STATUS);

        // 存入请求信息
        Long applyRecordId = schedulingApplyRecordService.submitRecord(schedulingApplyRecordDto);
        schedulingApplyRecordDto.setId(applyRecordId);
        schedulingApplyBusiness.pushMsg(schedulingApplyRecordDto, null, SchedulingApplyConstants.CURRENT_AT_SEQ_OF_BEGIN);

        return Response.ok();
    }

    private SchedulingApplyRecordDto initRecord(Byte applyType, SchedulingApplyRecordDto.BaseFormData formData, SchedulingApplyRecordDto dbRecord) {
        SchedulingApplyRecordDto schedulingApplyRecordDto = new SchedulingApplyRecordDto();

        schedulingApplyRecordDto.setId(dbRecord != null ? dbRecord.getId() : null);
        schedulingApplyRecordDto.setTenantId(SessionHolder.getEmp().getTenantId());
        schedulingApplyRecordDto.setVillageId(SessionHolder.getEmp().getVillageId());
        schedulingApplyRecordDto.setOrderNo(dbRecord == null ? OrderUtils.getOrderNo(OrderCodePrefixConstants.SCHEDULING_APPLY_PREFIX) : dbRecord.getOrderNo());
        schedulingApplyRecordDto.setApplyDeptPersonId(SessionHolder.getEmp().getId());
        schedulingApplyRecordDto.setApplyType(applyType);
        schedulingApplyRecordDto.setFormDataJson(JacksonUtils.toJsonString(formData));
        schedulingApplyRecordDto.setCurrentAtSeq(SchedulingApplyConstants.CURRENT_AT_SEQ_OF_BEGIN);
        schedulingApplyRecordDto.setCreator(SessionHolder.getEmp().getName());
        schedulingApplyRecordDto.setCreateTime(dbRecord != null ? dbRecord.getCreateTime() : new Date());
        schedulingApplyRecordDto.setEditor(SessionHolder.getEmp().getName());
        schedulingApplyRecordDto.setEditTime(dbRecord != null ? new Date() : null);
        return schedulingApplyRecordDto;
    }


    /**
     * 保存文件到miniIO
     *
     * @param extFiles 附件
     * @return
     */
    private Response<List<FileDataVO>> saveFileToMiniIO(MultipartFile[] extFiles) {
        //处理图片,将文件写入临时文件夹
        Response<List<String>> imgFilePathsResponse = fileBusiness.handleFileToTempPaths(extFiles, SchedulingApplyConstants.FILE_ACCEPT_TYPE);
        if (!imgFilePathsResponse.isSuccess()) {
            return Response.error(imgFilePathsResponse.getMessage());
        }
        //保存图片到MimiIO
        Response<List<FileDataVO>> fileDataResponse = fileBusiness.batchUploadFileAndGetFileData(imgFilePathsResponse.getData());
        if (!fileDataResponse.isSuccess()) {
            return Response.error(fileDataResponse.getMessage());
        }
        return fileDataResponse;
    }


    /**
     * 合并新增文件和原始文件
     *
     * @param newList    新增文件列表
     * @param formData   表单数据
     * @param dbFormData 原始表单数据
     * @return
     */
    private List<FileDataVO> mergeFileList(List<FileDataVO> newList, SchedulingApplyRecordDto.BaseFormData formData, SchedulingApplyRecordDto.BaseFormData dbFormData) {
        List<FileDataVO> result = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(newList)) {
            result.addAll(newList);
        }
        if (formData != null && CollectionUtils.isNotEmpty(formData.getExtFiles())) {
            result.addAll(formData.getExtFiles());
        }
        if (dbFormData != null && CollectionUtils.isNotEmpty(dbFormData.getExtFiles())) {
            result.addAll(dbFormData.getExtFiles());
        }

        //去重
        if (CollectionUtils.isNotEmpty(result)) {
            return result.stream().filter(fileDataVO -> StringUtils.isNoneBlank(fileDataVO.getUrl()))
                    .filter(distinctByKey(FileDataVO::getUrl))
                    .collect(Collectors.toList());
        } else {
            return result;
        }

    }

    private static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return obj -> seen.putIfAbsent(keyExtractor.apply(obj), Boolean.TRUE) == null;
    }

    /**
     * 是否包含附件标识,任意一个有文件列表都算有附件
     *
     * @param extFiles   附件列表
     * @param formData   提交的表单数据
     * @param dbFormData 原始表单数据
     * @return
     */
    private Byte getExtFilesFlag(MultipartFile[] extFiles, SchedulingApplyRecordDto.BaseFormData formData, SchedulingApplyRecordDto.BaseFormData dbFormData) {
        return ArrayUtil.isNotEmpty(extFiles) || (formData != null && ArrayUtil.isNotEmpty(formData.getExtFiles())) || (dbFormData != null && ArrayUtil.isNotEmpty(dbFormData.getExtFiles())) ? SystemConstants.YES : SystemConstants.NO;
    }


    /**
     * 提交审批记录
     *
     * @return
     */
    @PostMapping(value = "saveOrUpdateDraft", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    @Operation(summary = "修改申请记录,草稿可以修改申请记录,然后提交")
    public Response saveOrUpdateDraft(
            @Parameter(description = "recordId") @RequestParam(value = "recordId", required = false) Long recordId,
            @Parameter(description = "审核类型") @RequestParam(value = "applyType") Byte applyType,
            @Parameter(description = "表单内容") @RequestParam(value = "formData") String formDataJson,
            @Parameter(description = "文件列表") @RequestParam(value = "extFiles", required = false) MultipartFile[] extFiles
    ) {
        SessionHolder.checkEmp();

        SchedulingApplyRecordDto dbRecord = null;
        SchedulingApplyRecordDto.BaseFormData dbFormData = null;
        if (recordId != null) {
            dbRecord = schedulingApplyRecordService.selectById(recordId);
            Response response = schedulingApplyBusiness.checkDraft(dbRecord, SessionHolder.getEmp().getId());
            if (!response.isSuccess()) {
                return Response.error(response.getMessage());
            }

            dbFormData = dbRecord.getFormData();
        }

        SchedulingApplyRecordDto.BaseFormData formData = schedulingApplyBusiness.getFormData(applyType, formDataJson);
        if (formData == null) {
            return Response.error("提交数据有误");
        }
        //是否有附件的标识
        formData.setExtFileFlag(getExtFilesFlag(extFiles, formData, dbFormData));
        formData.setPersonId(SessionHolder.getEmp().getId());
        //打包申请时长
        formData = schedulingApplyBusiness.packTimeLength(applyType, formData);
        if (formData == null) {
            return Response.error("提交数据有误");
        }

        //保存到miniIO
        Response<List<FileDataVO>> saveFileResult = saveFileToMiniIO(extFiles);
        if (!saveFileResult.isSuccess()) {
            return Response.error(saveFileResult.getMessage());
        }
        formData.setExtFiles(mergeFileList(saveFileResult.getData(), formData, dbFormData));

        //保存记录
        SchedulingApplyRecordDto schedulingApplyRecordDto = initRecord(applyType, formData, dbRecord);
        schedulingApplyRecordDto.setStatus(SchedulingApplyConstants.NOT_SUBMITTED_STATUS);

        // 存入请求信息
        if (dbRecord == null) {
            schedulingApplyRecordService.save(schedulingApplyRecordDto);
        } else {
            schedulingApplyRecordService.updateById(schedulingApplyRecordDto);
        }
        return Response.ok();
    }


    @PostMapping("cancel/{id}")
    @Operation(summary = "撤回审批")
    public Response<Object> cancel(@PathVariable("id") Long id) {
        SessionHolder.checkEmp();
        //查询记录
        Map<String, Object> params = new HashMap<>();
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getTenantId), SessionHolder.getEmp().getTenantId());
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getVillageId), SessionHolder.getEmp().getVillageId());
        params.put(LambdaUtil.getFieldName(SchedulingApplyRecordDto::getApplyDeptPersonId), SessionHolder.getEmp().getId());
        if (schedulingApplyRecordService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        SchedulingApplyRecordDto schedulingApplyRecordDto = schedulingApplyRecordService.selectById(id);
        if (schedulingApplyRecordDto == null) {
            return Response.error("审批记录不存在");
        }
        //如果不是待审核状态则无法撤回
        if (!SchedulingApplyConstants.INIT_STATUS.equals(schedulingApplyRecordDto.getStatus())) {
            return Response.error("当前审批记录不可撤回");
        }
        //如果当前节点不是初始节点,则无法撤回
        if (!SchedulingApplyConstants.CURRENT_AT_SEQ_OF_BEGIN.equals(schedulingApplyRecordDto.getCurrentAtSeq())) {
            return Response.error("当前审批记录不可撤回");
        }

        schedulingApplyRecordService.cancel(id);

        return Response.ok();
    }

}
